home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
master
/
Examples
/
Visual
/
VMake
/
gadgets.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-01
|
40KB
|
1,086 lines
#include "vmake.h"
Prototype int init_gadgets(void);
Prototype void free_gadget(struct Gadget *gadget);
Prototype void free_gadlist(struct GADLIST *gadlist);
Prototype struct Gadget *create_gadget(struct GADLIST *gadlist,struct G_OBJECT *object,int ulx, int uly,int width);
Prototype void setup_string_gadget(struct Gadget *gad,int base);
Prototype struct Gadget *setup_cycle_gadget(struct Gadget *gad,struct IntuiText *itext,struct G_VALUE *val);
Prototype void reset_list_object(struct G_LIST *list,int active);
Prototype int setup_list_object(struct GADLIST *gadlist,struct Gadget *gad);
Prototype struct GADLIST *layout_gadgets(struct G_OBJECT *objlist, int ulx, int uly, int width);
Prototype struct Border *build_border(int width, int height, int mode);
Prototype int init_gad_sizes(int swidth, int sheight, int resize);
Prototype int create_borders(void);
Prototype int recalc_group_sizes(struct G_OBJECT *objlist, int *titsize, int *cycsize);
Prototype int text_width(char *str);
/***********************************************************************************
* Procedure: init_gadgets
* Synopsis: rc = init_gadgets();
* Purpose: Set up all the base system gadgets for the window. This includes all
* The user defined gadgets as well as the three buttons on the bottom
***********************************************************************************/
int init_gadgets()
{
struct Gadget *gad;
struct IntuiText *itext;
int ulx, uly;
int i;
int buttons;
global.gadlist = layout_gadgets(global.objects,
global.ri.WindowLeft,
global.ri.WindowTitle,
global.cycsize+global.titsize
);
if (global.gadlist == NULL) return(1);
ulx = global.ri.WindowLeft;
uly = global.height - global.ri.WindowBottom - global.iheight;
buttons = (global.width - (global.ri.WindowLeft + global.ri.WindowRight)) / BUTTON_WIDTH;
if (buttons > 5) buttons = 5;
for(i = 0; i < buttons; i++)
{
global.button[i].base.class = CLASS_BUTTON;
global.button[i].base.state = i; /* Note that these values correspond to */
/* the BUTTON_xxx equates */
gad = create_gadget(NULL, (struct G_OBJECT *)(global.button+i),
ulx, uly, BUTTON_WIDTH);
if (gad == NULL) return(1);
gad->GadgetRender = build_border(BUTTON_WIDTH,
global.iheight, MODE_OUT);
itext = gad->GadgetText;
itext->LeftEdge += (BUTTON_WIDTH - IntuiTextLength(itext))/2;
gad->NextGadget = global.gadlist->gadgets;
global.gadlist->gadgets = gad;
global.gadlist->count++;
gad->GadgetType = BOOLGADGET;
ulx += (global.width - (global.ri.WindowLeft +
global.ri.WindowRight +
(buttons*BUTTON_WIDTH)
)
) / (buttons-1) + BUTTON_WIDTH;
}
return(0);
}
/***********************************************************************************
* Procedure: free_gadget
* Synopsis: free_gadget(gadget)
* Purpose: Free up all memory associated with a gadget
***********************************************************************************/
void free_gadget(struct Gadget *gadget)
{
struct G_OBJECT *obj;
if (gadget)
{
obj = (struct G_OBJECT *)(gadget->UserData);
obj->gadget = NULL;
if (obj->class == CLASS_STRING)
{
/* We need to free the border structure also */
}
free_mem(gadget, sizeof(struct Gadget)+sizeof(struct IntuiText));
}
}
/***********************************************************************************
* Procedure: free_gadlist
* Synopsis: free_gadlist(gadlist)
* Purpose: Free up all memory associated with a gadget list created by
* layout_gadgets
***********************************************************************************/
void free_gadlist(struct GADLIST *gadlist)
{
struct Gadget *gad, *nextgad;
struct G_CYCLE *cyc;
struct G_STRING *str;
if (!gadlist) /* never allocated or already freed */
return;
for(gad = gadlist->gadgets; gad && gadlist->count; gad = nextgad, gadlist->count--)
{
nextgad = gad->NextGadget;
cyc = (struct G_CYCLE *)gad->UserData;
if ((cyc->base.class & CLASS_MASK) == CLASS_CYCLE)
{
/* If there is a string gadget currently in the cycle gadget, we need */
/* to free it up */
if ((str = cyc->curval->string) != NULL)
{
free_gadget(str->base.gadget);
}
}
free_gadget(gad);
}
free_mem(gadlist, sizeof(struct GADLIST));
}
/***********************************************************************************
* Procedure: create_gadget
* Synopsis: Gadget = create_gadget(gadlist, object, ulx, uly, width)
* Purpose: Create all the appropriate gadgetry and image structures for a list
* of gadgets.
***********************************************************************************/
struct Gadget *create_gadget(struct GADLIST *gadlist,
struct G_OBJECT *object,
int ulx, int uly,
int width
)
{
struct Gadget *gad;
struct IntuiText *itext;
/* Create a gadget structure and an associated intuitext structure to be */
/* Layed out on the screen */
gad = (struct Gadget *)get_mem(sizeof(struct Gadget)+sizeof(struct IntuiText));
if (gad)
{
itext = (struct IntuiText *)(gad+1);
gad->LeftEdge = ulx;
gad->TopEdge = uly;
gad->Width = width;
gad->Height = global.iheight;
gad->Flags = GADGHCOMP;
gad->Activation = RELVERIFY;
gad->GadgetText = itext;
gad->UserData = (APTR)object;
gad->GadgetID = object->class; /* set both class and subclass */
gad->GadgetType = BOOLGADGET;
object->gadget = gad;
/* Now we fill in the Intuitext structure */
itext->FrontPen = 1;
itext->BackPen = 0;
itext->DrawMode = JAM1;
itext->LeftEdge = 0;
itext->TopEdge = (global.iheight - global.ri.FontSize) / 2;
itext->ITextFont = &global.ri.TextAttr;
itext->IText = object->title;
itext->NextText = NULL;
if (gadlist)
{
gad->NextGadget = gadlist->gadgets;
gadlist->gadgets = gad;
gadlist->count++;
}
}
return(gad);
}
/***********************************************************************************
* Procedure: setup_string_gadget
* Synopsis: setup_string_gadget(gad, string, ulx, uly, width, base)
* Purpose: Create all the appropriate gadgetry and image structures for a list
* of gadgets.
***********************************************************************************/
void setup_string_gadget(struct Gadget *gad,
int base
)
{
int wraps;
int i;
struct Border *border;
struct StringInfo *si;
int sluff;
if (gad == NULL) return;
wraps = (base == CLASS_STRING) ? 2 : 1;
gad->LeftEdge += VBAR*wraps;
gad->TopEdge += DHBAR;
gad->Width -= DVBAR*wraps;
gad->Height -= 2*DHBAR;
sluff = (gad->Height - global.ri.FontSize);
if (sluff < 0) sluff = 0;
gad->Height = global.ri.FontSize;
gad->TopEdge += sluff / 2;
if (gad->GadgetText)
{
gad->GadgetText->TopEdge -= (DHBAR+sluff);
gad->GadgetText->LeftEdge -= VBAR*wraps;
}
if ((base == CLASS_LIST) ||
(base == CLASS_STRING) ||
(base == CLASS_CYCLE))
{
for(i=wraps; i > 0; i--)
{
/* We need to put a border around the gadget. */
/* For some string gadgets, we only need a single border */
/* We can tell this by the base type */
border = build_border(gad->Width+4*i, gad->Height + sluff + 2*i,
(i == 1) ? MODE_IN : MODE_OUT);
if (border != NULL)
{
border->NextBorder->LeftEdge = border->LeftEdge = -2*i;
border->NextBorder->TopEdge = border->TopEdge = -1*i - (sluff/2);
border->NextBorder->NextBorder = gad->GadgetRender;
gad->GadgetRender = border;
}
}
}
/* Lastly, we need to setup up the SpecialInfo structure for the string gadget */
/* If for some reason this fails, we will turn it into a button gadget */
si = (struct StringInfo *)get_mem(sizeof(struct StringInfo));
if (si != NULL)
{
gad->SpecialInfo = (APTR)si;
gad->GadgetType = STRGADGET;
si->Buffer = ((struct G_STRING *)(gad->UserData))->buf;
si->MaxChars = MAX_STRING;
}
else
gad->GadgetType = BOOLGADGET;
}
/***********************************************************************************
* Procedure: setup_cycle_gadget
* Synopsis: gadget = setup_cycle_gadget(gadget, value)
* Purpose: Create any subtending string gadgets and correctly position any
* cycle value text
***********************************************************************************/
struct Gadget *setup_cycle_gadget(struct Gadget *gad,
struct IntuiText *itext,
struct G_VALUE *val
)
{
struct Gadget *strgad;
int ilen;
ilen = IntuiTextLength(itext);
if (val->string)
{
int x, width;
itext->LeftEdge = CYC_ICON_WIDTH + 2;
/* We need to create a string gadget to get the input text from */
x = itext->LeftEdge + ilen;
width = gad->Width - x - 2;
/* Now, create a string gadget and border to put around the gadget */
strgad = create_gadget(NULL, (struct G_OBJECT *)val->string,
gad->LeftEdge+x, gad->TopEdge, width);
if (strgad)
{
setup_string_gadget(strgad, CLASS_CYCLE);
}
}
else
{
strgad = NULL;
itext->LeftEdge = (CYC_ICON_WIDTH + gad->Width - ilen) / 2;
}
return(strgad);
}
/***********************************************************************************
* Procedure: reset_list_object
* Synopsis: void reset_list_object(list,active);
* Purpose: Initialize all the appropriate text pointers for a list gadget
***********************************************************************************/
void reset_list_object(struct G_LIST *list,
int active
)
{
struct G_ENTRY *ent;
int i;
ent = list->top;
/* Run through all the entries visible on the screen and for each */
/* one that is displayed, mark the gadget as selectable. */
for(i = 0; i < global.listsize; i++)
{
/*
list->btngad[i]->Flags = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
GADGHNONE;
*/
list->btngad[i]->Flags = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
GADGHCOMP;
list->btngad[i]->Height = global.eheight;
list->strgad[i]->GadgetRender = NULL;
((struct StringInfo *)list->strgad[i]->SpecialInfo)->Buffer
= global.defbuf; /* because RefreshGlist might write to it... */
/* global.defbuf[0] = 0; */ /* want this to work like a null string */
/* Is there an entry corresponding to this position on the screen? */
if (ent)
{
/* Certainly is an entry, is it where they want a string gadget ? */
if (i == active)
{
/* Yes, shrink the gadget out of existence so that it doesn't */
/* appear on the screen. */
/* prevent mouse activation ?
list->btngad[i]->Height = 1;
*/
list->strgad[i]->GadgetRender = list->sborder;
}
/* else */
{
list->btngad[i]->Flags = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
GADGHCOMP;
}
((struct StringInfo *)
list->strgad[i]->SpecialInfo)->Buffer = ent->buf;
ent = (struct G_ENTRY *)ent->base.next;
}
}
}
/***********************************************************************************
* Procedure: setup_list_object
* Synopsis: ulx = setup_list_object(gadlist, gadget)
* Purpose: Create all the appropriate gadgetry and image structures for a list
* object
***********************************************************************************/
int setup_list_object(struct GADLIST *gadlist,
struct Gadget *gad
)
{
int ulx, uly, alen, dlen, ilen;
struct G_LIST *list;
int i;
char *savetitle;
struct Gadget *slider, *dngad, *upgad, *addgad, *delgad;
struct PropInfo *pi;
#define ARR_HEIGHT (7+DHBAR)
#define PROP_WIDTH (14+DVBAR)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* A list object consists of 8 separate gadgets arranged as below*/
/* 1: Boolean gadgets that overlay string gadgets. When the */
/* 2: string gadget is to be active, the height of the boolean */
/* 3: gadget is set to 1 exposing the string gadget. */
/* 4: A slider gadget to allow positioning in the list */
/* 5: An up arrow gadget for moving up one item in the list */
/* 6: A Down arrow gadget for moving down one item in the list */
/* 7: A NEW gadget for creating an entry in front of current item*/
/* 8: A DEL gadget for removing the current item from the list. */
/* */
/* */
/* TITLE TEXT */
/* ............................................}+---+ */
/* ::+---------------------------------------+}}|4 | */
/* ::|1 |}}| | */
/* ::| I T E M 1 |}}| | */
/* ::+---------------------------------------+}}| _ |+-------+ */
/* ::+---------------------------------------+}}|[_]||7 | */
/* ::|2 |}}| || N E W | */
/* ::| I T E M 2 |}}+---+| | */
/* ::+---------------------------------------+}}|5^ |+-------+ */
/* ::+---------------------------------------+}}|/ \|+-------+ */
/* ::|3 |}}+---+|8 | */
/* ::| I T E M 3 |}}|\ /|| D E L | */
/* ::+---------------------------------------+}}|6V || | */
/* :}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}+---++-------+ */
/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
list = (struct G_LIST *)gad->UserData;
/* We need to figure out how big the NEW and DEL gadgets will be */
alen = ilen = text_width(global.text[TEXT_NEW]);
dlen = text_width(global.text[TEXT_DEL]);
if (dlen > ilen) ilen = dlen;
ilen += 2*DHBAR;
gad->GadgetText->TopEdge = -global.ri.FontSize;
gad->TopEdge += global.ri.FontSize;
gad->Width -= ilen + PROP_WIDTH;
gad->Height = global.listsize*global.eheight + global.listextra;
gad->Flags = GADGHNONE;
gad->GadgetRender = build_border(gad->Width,
gad->Height,
MODE_OUT);
savetitle = list->base.title;
list->base.title = "";
uly = gad->TopEdge;
ulx = gad->LeftEdge + gad->Width;
/* Create the slider and two arrow gadgets. We will steal the */
/* first itext structure and throw it on to the main gadget */
slider = create_gadget(gadlist, (struct G_OBJECT *)list,
ulx+DVBAR, uly+DHBAR, PROP_WIDTH-2*DVBAR );
if (slider == NULL) return(0);
list->slider = slider;
slider->Height = global.listextra + global.listsize*global.eheight -
2*ARR_HEIGHT - 2*DHBAR;
slider->GadgetID = CLASS_PROP;
slider->GadgetType = PROPGADGET;
slider->Activation |= (GACT_IMMEDIATE | GACT_RELVERIFY | GACT_FOLLOWMOUSE);
pi = (struct PropInfo *)get_mem(sizeof(struct PropInfo)+
sizeof(struct Image));
if (pi == NULL) return(0);
slider->GadgetRender = (struct Image *)(pi+1);
slider->SpecialInfo = (APTR)pi;
pi->Flags = AUTOKNOB | FREEVERT | PROPBORDERLESS;
recalc_prop(list, &pi->VertBody, &pi->VertPot);
upgad = create_gadget(gadlist, (struct G_OBJECT *)list,
ulx, uly+slider->Height+2*DHBAR, PROP_WIDTH);
if (upgad == NULL) return(0);
upgad->Height = ARR_HEIGHT;
upgad->GadgetRender = &global.arrowborder[1];
upgad->GadgetID = CLASS_UP;
upgad->GadgetText = NULL;
dngad = create_gadget(gadlist, (struct G_OBJECT *)list,
ulx, upgad->TopEdge+ARR_HEIGHT, PROP_WIDTH);
if (dngad == NULL) return(0);
dngad->Height = ARR_HEIGHT;
dngad->GadgetRender = &global.arrowborder[0];
dngad->GadgetID = CLASS_DOWN;
dngad->GadgetText = NULL;
/* Create the ADD/DEL Buttons */
addgad = create_gadget(gadlist, (struct G_OBJECT *)list, ulx+PROP_WIDTH,
uly + global.listextra + global.listsize*global.eheight-2*global.iheight, ilen);
if (addgad == NULL) return(0);
addgad->GadgetRender = build_border(ilen, addgad->Height, MODE_OUT);
addgad->GadgetID = CLASS_ADD;
addgad->GadgetText->LeftEdge += (ilen-alen)>>1;
addgad->GadgetText->IText = global.text[TEXT_NEW];
delgad = create_gadget(gadlist, (struct G_OBJECT *)list, addgad->LeftEdge,
addgad->TopEdge+addgad->Height, ilen);
if (delgad == NULL) return(0);
list->delgad = delgad;
delgad->GadgetRender = addgad->GadgetRender;
delgad->GadgetID = CLASS_DEL;
if (list->first == NULL)
delgad->Flags |= GADGDISABLED;
delgad->GadgetText->LeftEdge += (ilen-dlen)>>1;
delgad->GadgetText->IText = global.text[TEXT_DEL];
for(i = 0; i < global.listsize; i++)
{
struct Gadget *tgad;
/* Create the string and button gadgets. Because we insert them on the */
/* List in reverse order and we want the button gadget to appear first, */
/* we need to create them in reverse order. */
/* This ordering is assumed in the state changing code. */
tgad = list->strgad[i] = create_gadget(gadlist,
(struct G_OBJECT *)list,
gad->LeftEdge+VBAR, uly,
gad->Width-DVBAR);
if (tgad == NULL) return(0);
tgad->GadgetText = NULL;
tgad->Height = global.eheight;
/* is this appropriate??? */
tgad->GadgetID = CLASS_LIST+(i<<SUBCLASS_OFF);
setup_string_gadget(tgad, CLASS_LIST);
tgad = list->btngad[i] = create_gadget(gadlist,
(struct G_OBJECT *)list,
gad->LeftEdge+VBAR, uly,
gad->Width-DVBAR);
if (tgad == NULL) return(0);
tgad->Height = global.eheight;
tgad->GadgetText = NULL;
tgad->GadgetID = CLASS_LIST+(i<<SUBCLASS_OFF);
uly += global.eheight;
}
list->sborder = list->strgad[0]->GadgetRender;
list->strgad[0]->GadgetRender = NULL;
/* Undo the damage we did to the base object */
list->base.title = savetitle;
list->base.gadget = gad;
reset_list_object(list, -1);
return(uly+global.listextra);
}
/***********************************************************************************
* Procedure: layout_gadgets
* Synopsis: gadlist = layout_gadgets(objlist, ulx, yly, width);
* Purpose: Create all the appropriate gadgetry and image structures for a list
* of gadgets.
***********************************************************************************/
struct GADLIST *layout_gadgets(struct G_OBJECT *objlist,
int ulx, int uly,
int width
)
{
struct Gadget *gad;
struct IntuiText *itext, *itext1;
int ilen;
struct G_OBJECT *obj;
struct GADLIST *gadlist;
if (create_borders()) return(NULL);
gadlist = (struct GADLIST *)get_mem(sizeof(struct GADLIST));
if (gadlist == NULL) return(NULL);
/* First we need to lay out the gadgets on the left side of the window */
for(obj = objlist; obj != NULL; obj = obj->next)
{
/* Make sure that the gadget will fit on the screen. We don't even pretend */
/* To handle the case of a list gadget going over */
if (uly > (global.height - global.ri.WindowBottom - 2*global.iheight))
return(gadlist);
/* Create a gadget structure and an associated intuitext structure to be */
/* Layed out on the screen */
gad = create_gadget(gadlist, obj, ulx, uly, width);
if (gad == NULL) return(gadlist);
itext = (struct IntuiText *)(gad+1);
uly += gad->Height;
ilen = IntuiTextLength(itext);
switch(obj->class)
{
case CLASS_STRING:
gad->LeftEdge += global.titsize;
gad->Width = global.cycsize;
itext->LeftEdge = -ilen;
setup_string_gadget(gad, CLASS_STRING);
break;
case CLASS_CYCLE:
gad->GadgetRender = global.cycborder;
gad->GadgetType = BOOLGADGET;
gad->LeftEdge += global.titsize;
gad->Width = global.cycsize;
itext->LeftEdge = -ilen;
itext1 = (struct IntuiText *)get_mem(sizeof(struct IntuiText));
if (itext1 == NULL) return(gadlist);
itext1->FrontPen = 1;
itext1->BackPen = 0;
itext1->DrawMode = JAM1;
itext1->LeftEdge = 0;
itext1->TopEdge = 3;
itext1->ITextFont = &global.ri.TextAttr;
itext1->IText = ((struct G_CYCLE *)obj)->curval->title;
itext1->NextText = NULL;
itext1->LeftEdge = (CYC_ICON_WIDTH+gad->Width-IntuiTextLength(itext1))/2;
itext->NextText = itext1;
itext1->IText = ((struct G_CYCLE *)obj)->curval->title;
break;
case CLASS_CHECK:
gad->GadgetType = BOOLGADGET;
gad->Width = CHECK_WIDTH;
gad->Height = CHECK_HEIGHT;
gad->Flags = GADGHIMAGE;
if (obj->state & STATE_MASK) gad->Flags |= SELECTED;
gad->Activation |= TOGGLESELECT;
gad->GadgetRender = global.checkborder[0];
gad->SelectRender = global.checkborder[1];
itext->LeftEdge += CHECK_WIDTH + 4;
break;
case CLASS_LIST:
uly = setup_list_object(gadlist, gad);
if (uly <= 0) return(gadlist);
break;
default:
gad->GadgetType = BOOLGADGET;
break;
}
}
return(gadlist);
}
/***********************************************************************************
* Procedure: build_border
* Synopsis: Border = build_border(width, height, mode)
* Purpose: Build an return a set of drawing vectors that represent a button of
* width and height. Mode can be either MODE_OUT or MODE_IN
***********************************************************************************/
struct Border *build_border(int width,
int height,
int mode
)
{
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* */
/* Select the colors based on the rendering mode. For an out box, we will use */
/* the lighter color on the upper and left sides and the darker color on the */
/* other two sides. In an in box, the choice is reversed. */
/* (x,y) 5 */
/* 1****************************************************.2 */
/* **4 3.. */
/* ** .. */
/* ** .. */
/* ** .. */
/* ** .. */
/* **3 5 4.. */
/* 2*....................................................1 */
/* (x+width, y+height) */
/* 0. 0, 0 10. wd, ht */
/* 2. 0, ht 12. wd, 0 */
/* 4. 1, ht-1 14. wd-1, 1 */
/* 6. 1, 0 16. wd-1, ht */
/* 8. wd-1, 0 18. 1, ht */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct Border *border, *border1;
short *vecs;
int i;
static short inits[] = { 0, 0, 0, 0, 1,-1, 1, 0, -1, 0,
0, 0, 0, 0, -1, 1, -1, 0, 1, 0};
#define VEC_COUNT 5
#define SINGLEUNIT (sizeof(struct Border)+sizeof(inits))
width--;
height--;
border = (struct Border *)get_mem(2*SINGLEUNIT);
if (border == NULL) return(NULL);
border1 = border+1;
vecs = (short *)(border+2);
border->NextBorder = border1;
border->DrawMode = JAM1;
border->Count = VEC_COUNT;
border->XY = vecs;
border1->DrawMode = JAM1;
border1->Count = VEC_COUNT;
border1->XY = vecs + (2*VEC_COUNT);
memcpy((char *)vecs, (char *)inits, sizeof(inits));
for(i = 8; i < 17; i += 2) vecs[i] += width;
vecs[3] += height;
vecs[5] += height;
vecs[11] += height;
vecs[17] += height;
vecs[19] += height;
if (mode == MODE_OUT)
{
border1->FrontPen = global.ri.Shadow;
border->FrontPen = global.ri.Highlight;
}
else
{
border1->FrontPen = global.ri.Highlight;
border->FrontPen = global.ri.Shadow;
}
return(border);
}
/***********************************************************************************
* Procedure: init_gad_sizes
* Synopsis: rc = init_gad_sizes(swidth, sheight, resize);
* Purpose: Calculate and initialize all the imagery structures
***********************************************************************************/
int init_gad_sizes(int swidth,
int sheight,
int resize)
{
int i;
int width, height, wextra, wmarg;
static int savewidth, saveheight;
wmarg = MARGIN_LEFT + MARGIN_RIGHT;
if (!resize) /* not resizing */
if (savewidth) /* and we already have a size */
if ((savewidth < swidth) && (saveheight < sheight))
{ /* and it will fit this screen */
swidth = savewidth;
sheight = saveheight;
resize = 1; /* trust me... */
}
wmarg += RESIZE_WIDTH + MARGIN_LEFT;
global.listsize = 0;
/* Make two passes attempting to layout the items. The first time we will use */
/* Whatever the prevailing font is. If this doesn't work, we will switch to a */
/* Simple TOPAZ80 and try again. Only if that fails will we give up. */
for(i = 5; i >= 0; i--)
{
global.iheight = global.ri.TextAttr.ta_YSize+DHBAR;
/* debug - why not try believing TextAttr ? */
/*
if (global.iheight < global.ri.FontSize)
global.iheight = global.ri.FontSize;
*/
if (global.iheight < global.ri.FontSize)
global.ri.FontSize = global.iheight;
if (i)
{
global.iheight += 4; /* Account for decent margins on the rendering */
global.eheight = global.ri.FontSize + 2*DHBAR;
global.listextra = 0;
}
else
{
global.iheight += 2; /* Account for decent margins on the rendering */
global.eheight = global.ri.FontSize + DHBAR + HBAR;
global.listextra = 1;
}
/* We have the totals for everything, let's figure out how */
/* big the final thing is going to be. */
height = recalc_group_sizes(global.objects, &global.titsize, &global.cycsize)+
global.iheight + MARGIN_MID + /* Gadgets on the bottom */
global.ri.WindowTitle + global.ri.WindowBottom;
width = global.cycsize + global.titsize + wmarg;
if ((wextra = (width - swidth)) > 0)
{
if (wextra < global.titsize)
global.titsize -= wextra;
else
global.titsize = 0;
}
if ((i == 5) && (height <= sheight))
{
int num;
num = (sheight - height) / global.eheight;
if (num < 3)
{
height = sheight + 1; /* Force a failure */
}
else
{
if (!resize) /* first time in go for medium size */
{
if (num > 10) num = 10;
}
else
if (num > MAX_LIST) num = MAX_LIST;
global.listsize = num;
height += num*global.eheight;
}
}
if (height <= sheight) break;
/* can we do anything here about insufficient width ? */
switch(i)
{
case 0:
break;
case 1:
case 2:
/* Set up so we try with Topaz 80 as our default font the second time around */
global.ri.TextAttr = TOPAZ80;
break;
case 5:
global.listsize = 9;
break;
default:
global.listsize = (global.listsize / 2) + 1;
if (global.listsize < 3) global.listsize = 3;
break;
}
}
/* Everything worked out fine, let us set the height of the window */
global.width = resize ? swidth : width;
global.height = resize ? sheight : height;
savewidth = global.width;
saveheight = global.height;
/* Also see if we need to adjust the titsize and cycsize values */
i = global.width - width;
if (i > 0)
global.cycsize += i;
return(0);
}
/***********************************************************************************
* Procedure: create_borders
* Synopsis: create_borders
* Purpose: Create the borders for all the gadgets
***********************************************************************************/
int create_borders()
{
struct Border *border;
/* * * * * * * * * * * * * * * * * * * * * * * * * * */
/* */
/* 11111111 11111111 */
/* 012345678901234567 012345678901234567 */
/* =================# =================# 0 */
/* ||......23......## ||..18......54..## 1 */
/* ||......##......## ||..##......##..## 2 */
/* ||.....####.....## ||...##....##...## 3 */
/* ||....##76##....## ||....##76##....## 4 */
/* ||...##....##...## ||.....####.....## 5 */
/* ||..##......##..## ||......##......## 6 */
/* ||..18......54..## ||......23......## 7 */
/* |################# |################# 8 */
/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * */
static short Up_Vectors[] = { 4,6, 8,2, 9,2, 13,6, 12,6, 9,3, 8,3, 5,6 };
static short Dn_Vectors[] = { 4,2, 8,6, 9,6, 13,2, 12,2, 9,5, 8,5, 5,2 };
/* * * * * * * * * * * * * * * * * * */
/* 11111111112222 */
/* 012345678901234567890134 */
/* ========================== 0 */
/* ||.....7.....8.......... 1 */
/* ||.....#######......#|.. 2 */
/* ||...5##.....##d....#|.. 3 */
/* ||....##.....##.....#|.. 4 */
/* ||....##..a######b..#|.. 5 */
/* ||....##....####....#|.. 6 */
/* ||....##....9##c....#|.. 7 */
/* ||....##............#|.. 8 */
/* ||...4##6...0##1....#|.. 9 */
/* ||.....#######......#|.. 10 */
/* ||.....3.....2.......... 11 */
/* |######################## 12 */
/* */
/* * * * * * * * * * * * * * * * * * */
static short Cycle_Vectors[] = { 13, 9, 14, 9, 13,10, 7,10, 6, 9,
6, 3, 7, 9, 7, 2, 13, 2, 13, 7,
11, 5, 16, 5, 14, 7, 14, 3, };
static short Cycle_Line1[] = { 20, 2, 20,11};
static short Cycle_Line2[] = { 21, 2, 21,11};
static short Check_Vectors[] = { 19, 2, 17, 2, 11, 8, 8, 5, 7, 5,
10, 8, 9, 5, 12, 8, 18, 2 };
/* Now we have calculated sizes for the objects, layout the border structures */
/* Create a border for the cycle gadgets */
global.cycborder = build_border(global.cycsize,
global.iheight, MODE_OUT);
/* We also need to put in the vectors for the cycle picture */
border = (struct Border *)get_mem(5*sizeof(struct Border));
if (border == NULL) return(1);
border[0].NextBorder = border+1;
border[1].NextBorder = border+2;
border[2].NextBorder = global.cycborder;
global.cycborder = border;
border[0].DrawMode = JAM1;
border[0].Count = sizeof(Cycle_Vectors)/(2*sizeof(short));
border[0].XY = Cycle_Vectors;
border[0].FrontPen = 1;
border[1].DrawMode = JAM1;
border[1].Count = sizeof(Cycle_Line1)/(2*sizeof(short));
border[1].XY = Cycle_Line1;
border[1].FrontPen = global.ri.Shadow;
border[2].DrawMode = JAM1;
border[2].Count = sizeof(Cycle_Line2)/(2*sizeof(short));
border[2].XY = Cycle_Line2;
border[2].FrontPen = global.ri.Highlight;
global.checkborder[0] = border+3;
border[3].NextBorder = build_border(CHECK_WIDTH, CHECK_HEIGHT, MODE_OUT);
border[3].DrawMode = JAM1;
border[3].Count = sizeof(Check_Vectors)/(2*sizeof(short));
border[3].XY = Check_Vectors;
border[3].FrontPen = 0;
global.checkborder[1] = border+4;
border[4].NextBorder = build_border(CHECK_WIDTH, CHECK_HEIGHT, MODE_OUT);
border[4].DrawMode = JAM1;
border[4].Count = sizeof(Check_Vectors)/(2*sizeof(short));
border[4].XY = Check_Vectors;
border[4].FrontPen = 1;
/* Adjust the height of the cycle vectors to the current height */
/* See the picture above for these values. Yes, they are hard */
/* coded magic values, but equates for them don't make a lot of */
/* sense in a situation like this. */
{
int cheight;
if (global.iheight > 11)
cheight = global.iheight;
else
cheight = 11;
cheight -= DHBAR;
Cycle_Vectors[1] = cheight - 2;
Cycle_Vectors[3] = cheight - 2;
Cycle_Vectors[5] = cheight - 1;
Cycle_Vectors[7] = cheight - 1;
Cycle_Vectors[9] = cheight - 2;
Cycle_Vectors[13] = cheight - 2;
}
/*
for(i = 0; i < 0x0d; i++)
{
int extra;
extra = global.iheight - 13;
if (i > 8)
{
extra >>= 1;
}
else if ((i > 6) || (i == 5))
{
extra = 0;
}
Cycle_Vectors[1+i*2] += extra;
}
*/
Cycle_Line2[3] = Cycle_Line1[3] = (global.iheight - 1) - DHBAR;
{
int bheight;
bheight = (global.listsize*global.eheight) - (2*ARR_HEIGHT) + global.listextra;
border = build_border(PROP_WIDTH, bheight, MODE_OUT);
if (border == NULL) return(1);
border->TopEdge -= bheight;
border->NextBorder->TopEdge -= bheight;
}
global.arrowborder[0].NextBorder = build_border(PROP_WIDTH, ARR_HEIGHT, MODE_OUT);
global.arrowborder[1].NextBorder = border;
border->NextBorder->NextBorder = global.arrowborder[0].NextBorder;
global.arrowborder[0].DrawMode = JAM1;
global.arrowborder[0].Count = sizeof(Dn_Vectors)/(2*sizeof(short));
global.arrowborder[0].XY = Dn_Vectors;
global.arrowborder[0].FrontPen = 1;
global.arrowborder[1].DrawMode = JAM1;
global.arrowborder[1].Count = sizeof(Up_Vectors)/(2*sizeof(short));
global.arrowborder[1].XY = Up_Vectors;
global.arrowborder[1].FrontPen = 1;
return(0);
}
/***********************************************************************************
* Procedure: recalc_group_sizes
* Synopsis: recalc_group_sizes(objlist, &titsize, &cycsize)
* Purpose: Calculate the base sizes for different types of objects.
* We need to calculate the width for CYCLE titles and size for cycles
* Everything else has a fixed size to be used anyway.
***********************************************************************************/
int recalc_group_sizes(struct G_OBJECT *objlist,
int *titsize,
int *cycsize)
{
int wid;
int height;
struct G_OBJECT *obj;
struct G_CYCLE *cyc;
struct G_VALUE *val;
*titsize = 0;
*cycsize = 0;
height = 0;
/* First we need to lay out the gadgets on the left side of the window */
for(obj = objlist; obj != NULL; obj = obj->next)
{
switch(obj->class)
{
case CLASS_CYCLE:
/* go through and get all the cycle values */
cyc = (struct G_CYCLE *)obj;
set_cyc_state(cyc, cyc->curval);
for(val = cyc->values; val != NULL; val = val->next)
{
wid = text_width(val->title);
if (val->string)
{
char *p;
int num;
p = strchr(val->option, '%');
num = 0;
if (p)
{
p++;
while ((*p >= '0') && (*p <= '9'))
num = (num * 10) + *p++ - '0';
}
if (num <= 0) num = 3;
wid += (text_width("0") * (num+1)) + DVBAR;
}
if (wid > *cycsize) *cycsize = wid;
}
/* Fall through and get the title size */
case CLASS_STRING:
wid = text_width(obj->title);
if (wid > *titsize) *titsize = wid;
break;
case CLASS_LIST:
height += global.eheight * global.listsize;
break;
case CLASS_CHECK:
break;
default:
printf("Huh\n");
break;
}
height += global.iheight;
}
*titsize += DVBAR;
*cycsize += CYC_ICON_WIDTH+DVBAR;
return(height);
}
/***********************************************************************************
* Procedure: text_width
* Synopsis: len = text_width(str)
* Purpose: Return the rendered width of a given string
***********************************************************************************/
int text_width(char *str
)
{
struct IntuiText itext;
itext.FrontPen = 1;
itext.BackPen = 0;
itext.DrawMode = JAM1;
itext.LeftEdge = 0;
itext.TopEdge = 1;
itext.ITextFont = &global.ri.TextAttr;
itext.NextText = NULL;
itext.IText = str;
return(IntuiTextLength(&itext));
}